/*
 * Copyright (C) 2021 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the
 *       distribution.
 *    3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @addtogroup IotHardware
 * @{
 *
 * @brief Provides APIs for operating devices,
 * including flash, GPIO, I2C, PWM, UART, and watchdog APIs.
 *
 *
 *
 * @since 2.2
 * @version 2.2
 */
#include "iot_errno.h"
#include "iot_uart.h"
#include "driver/chip/hal_uart.h"

//#define UART_DMA_MODE
//#define UART_IT_MODE
#define UART_POLL_MODE

/**
 * @brief Configures a UART device with the port number specified by <b>id</b>
 * based on the basic and extended attributes.
 *
 *
 *
 * @param id Indicates the port number of the UART device.
 * @param param Indicates the pointer to the UART attributes.
 * @return Returns {@link IOT_SUCCESS} if the UART device is configured successfully;
 * returns {@link IOT_FAILURE} otherwise. For details about other return values, see the chip description.
 * @since 2.2
 * @version 2.2
 */
unsigned int IoTUartInit(unsigned int id, const IotUartAttribute *param)
{
    HAL_Status status = HAL_ERROR;
    UART_InitParam uart;

    if ((UART_ID)id >= UART_NUM) {
        printf("IoTUartInit id=%u error\r\n", id);
        return IOT_FAILURE;
    }

    if ((param->dataBits != IOT_UART_DATA_BIT_5) &&
        (param->dataBits != IOT_UART_DATA_BIT_6) &&
        (param->dataBits != IOT_UART_DATA_BIT_7) &&
        (param->dataBits != IOT_UART_DATA_BIT_8)) {
        printf("IoTUartInit param->dataBits=%d error\r\n",
               param->dataBits);
        return IOT_FAILURE;
    } else {
        switch (param->dataBits) {
        case IOT_UART_DATA_BIT_5:
            uart.dataBits = UART_DATA_BITS_5;
            break;

        case IOT_UART_DATA_BIT_6:
            uart.dataBits = UART_DATA_BITS_6;
            break;

        case IOT_UART_DATA_BIT_7:
            uart.dataBits = UART_DATA_BITS_7;
            break;

        case IOT_UART_DATA_BIT_8:
            uart.dataBits = UART_DATA_BITS_8;
            break;

        default:
            break;
        }
    }

    if ((param->stopBits != IOT_UART_STOP_BIT_1) &&
        (param->stopBits != IOT_UART_STOP_BIT_2)) {
        printf("IoTUartInit param->stopBits=%d error\r\n",
               param->stopBits);
        return IOT_FAILURE;
    } else {
        switch (param->stopBits) {
        case IOT_UART_STOP_BIT_1:
            uart.stopBits = UART_STOP_BITS_1;
            break;

        case IOT_UART_STOP_BIT_2:
            uart.stopBits = UART_STOP_BITS_2;
            break;

        default:
            break;
        }
    }

    if ((param->parity != IOT_UART_PARITY_NONE) &&
        (param->parity != IOT_UART_PARITY_ODD) &&
        (param->parity != IOT_UART_PARITY_EVEN)) {
        printf("IoTUartIniparam->parity=%d error\r\n", param->parity);
        return IOT_FAILURE;
    } else {
        switch (param->parity) {
        case IOT_UART_PARITY_NONE:
            uart.parity = UART_PARITY_NONE;
            break;

        case IOT_UART_PARITY_ODD:
            uart.parity = UART_PARITY_ODD;
            break;

        case IOT_UART_PARITY_EVEN:
            uart.parity = UART_PARITY_EVEN;
            break;

        default:
            break;
        }
    }

    uart.baudRate = param->baudRate;
    uart.isAutoHwFlowCtrl = 0;

    status = HAL_UART_Init((UART_ID)id, &uart);
    if (status != HAL_OK) {
        printf("uart init error %d\n", status);
        return IOT_FAILURE;
    }

#if (defined(UART_DMA_MODE))
    status = HAL_UART_EnableTxDMA((UART_ID)id);
    if (status != HAL_OK) {
        HAL_UART_DeInit((UART_ID)id);
        return IOT_FAILURE;
    }

    status = HAL_UART_EnableRxDMA((UART_ID)id);
    if (status != HAL_OK) {
        HAL_UART_DeInit((UART_ID)id);
        return IOT_FAILURE;
    }
#endif

    return IOT_SUCCESS;
}

/**
 * @brief Reads a specified length of data from a UART device with the port number specified by <b>id</b>.
 *
 *
 *
 * @param id Indicates the port number of the UART device.
 * @param data Indicates the pointer to the start address of the data to read.
 * @param dataLen Indicates the number of bytes to read.
 * @return Returns the number of bytes read if the operation is successful; returns <b>-1</b> otherwise.
 * @since 2.2
 * @version 2.2
 */
int IoTUartRead(unsigned int id, unsigned char *data, unsigned int dataLen)
{
    if ((UART_ID)id >= UART_NUM) {
        printf("IoTUartRead id=%u error\r\n", id);
        return IOT_FAILURE;
    }

#if (defined(UART_POLL_MODE))
    int ret = HAL_UART_Receive_Poll((UART_ID)id, data, dataLen, 1000);
#elif (defined(UART_IT_MODE))
    int ret = HAL_UART_Receive_IT((UART_ID)id, data, dataLen, 1000);
#elif (defined(UART_DMA_MODE))
    int ret = HAL_UART_Receive_DMA((UART_ID)id, data, dataLen, 1000);
#endif
    return ret;
}

/**
 * @brief Writes a specified length of data to a UART device with the port number specified by <b>id</b>.
 *
 *
 *
 * @param id Indicates the port number of the UART device.
 * @param data Indicates the pointer to the start address of the data to write.
 * @param dataLen Indicates the number of bytes to write.
 * @return Returns the number of bytes written if the operation is successful; returns <b>-1</b> otherwise.
 * @since 2.2
 * @version 2.2
 */
int IoTUartWrite(unsigned int id, const unsigned char *data,
         unsigned int dataLen)
{
    if ((UART_ID)id >= UART_NUM) {
        printf("IoTUartWrite id=%u error\r\n", id);
        return IOT_FAILURE;
    }

#if (defined(UART_POLL_MODE))
    int ret = HAL_UART_Transmit_Poll((UART_ID)id, (uint8_t *)data, dataLen);
#elif (defined(UART_IT_MODE))
    int ret = HAL_UART_Transmit_IT((UART_ID)id, (uint8_t *)data, dataLen);
#elif (defined(UART_DMA_MODE))
    int ret = HAL_UART_Transmit_DMA((UART_ID)id, (uint8_t *)data, dataLen);
#endif
    return ret;
}

/**
 * @brief Deinitializes a UART device.
 *
 * @param id Indicates the port number of the UART device.
 * @return Returns {@link IOT_SUCCESS} if the UART device is deinitialized;
 * returns {@link IOT_FAILURE} otherwise. For details about other return values, see the chip description.
 * @since 2.2
 * @version 2.2
 */
unsigned int IoTUartDeinit(unsigned int id)
{
    HAL_Status status = HAL_ERROR;

    if ((UART_ID)id >= UART_NUM) {
        printf("IoTUartDeinit id=%u error\r\n", id);
        return IOT_FAILURE;
    }

#if (defined(UART_DMA_MODE))
    status = HAL_UART_DisableTxDMA((UART_ID)id);
    if (status != HAL_OK) {
        printf("uart TX disenable DMA error %d\n", status);
    }

    status = HAL_UART_DisableRxDMA((UART_ID)id);
    if (status != HAL_OK) {
        printf("uart RX disenable DMA error %d\n", status);
    }
#endif

    status = HAL_UART_DeInit((UART_ID)id);
    if (status != HAL_OK) {
        printf("uart deinit error %d\n", status);
        return IOT_FAILURE;
    }

    return IOT_SUCCESS;
}

/**
 * @brief Sets flow control for a UART device with the port number specified by <b>id</b>.
 *
 *
 *
 * @param id Indicates the port number of the UART device.
 * @param flowCtrl Indicates the flow control parameters, as enumerated in {@link IotFlowCtrl}.
 * @return Returns {@link IOT_SUCCESS} if flow control is set successfully;
 * returns {@link IOT_FAILURE} otherwise. For details about other return values, see the chip description.
 * @since 2.2
 * @version 2.2
 */
unsigned int IoTUartSetFlowCtrl(unsigned int id, IotFlowCtrl flowCtrl)
{
    return IOT_SUCCESS;
}

/** @} */
